Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

action_sheet: Add "Mark topic as read" button #1274

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

lakshya1goel
Copy link
Contributor

@lakshya1goel lakshya1goel commented Jan 12, 2025

This PR adds a "Mark Topic as Read" button to the topic action sheet. The button appears only when there are unread messages in the topic.

Fixes #1225 and #1357

Screenshot

WhatsApp Image 2025-02-06 at 3 05 22 AM

Screen Recording

WhatsApp.Video.2025-02-06.at.3.05.49.AM.mp4

Additional

  • Updated icon for "Mark all messages as read button" from Icons.playlist_add_check to Icons.mark_chat_read_outlined

See CZO Discussion

Before After

@lakshya1goel lakshya1goel marked this pull request as draft January 12, 2025 16:17
@lakshya1goel lakshya1goel force-pushed the issue1225 branch 2 times, most recently from 56a877f to af14f10 Compare January 30, 2025 09:08
@lakshya1goel lakshya1goel marked this pull request as ready for review January 30, 2025 09:28
@lakshya1goel
Copy link
Contributor Author

Hello, I want to know that should I commit the change of icon of "Mark all messages as read button" separately?

@PIG208
Copy link
Member

PIG208 commented Jan 30, 2025

Yeah, committing it separately sounds good.

Copy link
Member

@PIG208 PIG208 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! Took a quick look at the implementation and left a comment.

@PIG208 PIG208 self-assigned this Jan 30, 2025
@PIG208 PIG208 added the maintainer review PR ready for review by Zulip maintainers label Jan 30, 2025
@alya
Copy link
Collaborator

alya commented Jan 31, 2025

Why is the icon different from the one we have in the web app?

Screenshot 2025-01-31 at 11 01 39

@lakshya1goel
Copy link
Contributor Author

Thanks Alya for pointing. I have updated the correct icon and also updated the PR description with latest screenshots.

@lakshya1goel lakshya1goel changed the title Offer Mark topic as read in topic action sheet action_sheet: Add "Mark Topic As Read" button Feb 1, 2025
@lakshya1goel lakshya1goel force-pushed the issue1225 branch 3 times, most recently from e45f627 to 59fb9c2 Compare February 1, 2025 09:27
@lakshya1goel lakshya1goel requested a review from PIG208 February 1, 2025 09:30
@lakshya1goel
Copy link
Contributor Author

Thanks for the review @PIG208, pushed the revision, PTAL.

Copy link
Member

@PIG208 PIG208 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! Went through the changes and left some comments, mainly on the tests.

@lakshya1goel
Copy link
Contributor Author

Thanks for the review @PIG208, I have updated the tests and the commit message accordingly. Please have a look and let me know if anything else is required.

Copy link
Member

@PIG208 PIG208 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update! Left review comments.

@lakshya1goel
Copy link
Contributor Author

Pushed the changes, Please have a look now @PIG208 , Thanks!

@PIG208
Copy link
Member

PIG208 commented Feb 5, 2025

Could you also post a screenshot of the topic action sheet with the mark topic as read button on there? For design changes, we prefer screenshots over screen recording, unless it is specific about some interaction. Even then, having both included is helpful.

@lakshya1goel
Copy link
Contributor Author

lakshya1goel commented Feb 5, 2025

Updated the description of PR with screenshot.

Copy link
Member

@PIG208 PIG208 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update! This mostly looks good to me, with some nits.

@lakshya1goel
Copy link
Contributor Author

Pushed the revision @PIG208, PTAL. Thanks!

@PIG208
Copy link
Member

PIG208 commented Feb 15, 2025

Looks good except for one more nit! Marking it for Greg's review.

@PIG208 PIG208 added integration review Added by maintainers when PR may be ready for integration and removed maintainer review PR ready for review by Zulip maintainers labels Feb 15, 2025
@PIG208 PIG208 assigned gnprice and unassigned PIG208 Feb 15, 2025
@PIG208 PIG208 requested a review from gnprice February 15, 2025 03:26
chimnayajith pushed a commit to chimnayajith/zulip-flutter that referenced this pull request Feb 15, 2025
Figma doesn't specify this icon explicitly. Based on discussions in PR zulip#1274
(zulip#1274 (comment)),
we chose this icon for consistency with the "Mark as read" option on web.

reference: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=3512-7&t=iwirdCVutQls9R0A-4
@lakshya1goel
Copy link
Contributor Author

lakshya1goel commented Feb 18, 2025

Hi @gnprice, Whenever you have some time, I would really appreciate it if you could review the PR. Thanks a lot!

Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @lakshya1goel for taking care of this, and thanks @PIG208 and all for the previous reviews! Comments below.

Let's leave out the last commit introducing ZulipAction; that change is mostly a matter of writing docs, so I think it'll be simpler if I just do that change myself rather than going through cycles of editing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did this icon file come from a particular place in the Figma design, or somewhere else?

Please mention the source in the commit message (with e.g. a Figma link). That helps us track where we've gotten our icons from.

Comment on lines 490 to 491
@override void onPressed() async {
if (!pageContext.mounted) return;
await ZulipAction.markNarrowAsRead(pageContext, TopicNarrow(channelId, topic));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this if-mounted check at the top isn't something we have in any of the comparable methods in this file. I think we can leave it out.

(If there is a reason we need it, then that reason will probably apply equally to all the other buttons.)

Was there a discussion about this in a previous round of review? It's a bit difficult for me to find out from the GitHub page, because of some of GitHub's UI choices. You can mitigate that by avoiding marking comments as "resolved", similar to what Chris said the other day elsewhere: #1317 (review)

Copy link
Contributor Author

@lakshya1goel lakshya1goel Feb 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this was not discussed in the previous round. Also, I will not mark the comments as resolved from now on.

testWidgets('visible if topic has unread messages', (tester) async {
await prepare();
final message = eg.streamMessage(stream: someChannel, topic: someTopic);
await store.handleEvent(MessageEvent(id: 0, message: message));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can simplify with a handy test helper:

Suggested change
await store.handleEvent(MessageEvent(id: 0, message: message));
await store.addMessage(message);

Comment on lines 573 to 572
testWidgets('visible if topic has unread messages', (tester) async {
await prepare();
final message = eg.streamMessage(stream: someChannel, topic: someTopic);
await store.handleEvent(MessageEvent(id: 0, message: message));
await showFromAppBar(tester, messages: [message]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is implicitly relying on the fact that eg.streamMessage returns a message which is unread (doesn't have the read flag).

In general, test cases should avoid depending on the specific default choices made by the functions in example_data — each test should be self-contained in that the reader should be able to understand the key logic of how it works just by reading the test itself (and any local helper functions specific to the test), without going and looking through the details of example_data.dart.

Instead, both this test and the others that care about whether the message is read or unread should explicitly pass flags to eg.streamMessage so that they control that fact about the message.

testWidgets('not visible if topic has no unread messages', (tester) async {
await prepare();
final message = eg.streamMessage(stream: someChannel, topic: someTopic);
await showFromAppBar(tester, messages: [message]);
check(find.text('Mark topic as read')).findsNothing();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit subtle, but the way this test currently works is depending on a bug. 🙂 Namely #649.

The only difference between the setup of this test and the one above it, which gets the opposite result, is that the other test has the message arrive first as an event and then via a fetch, while this one has it arrive only via a fetch. In both cases the message is unread. If we fetch some messages and one of them is described as unread (it lacks the read flag), then logically there is an unread message in that topic, and the fact that we don't put it into our data structures as such is a bug (namely #649).

So let's instead have this test set things up in a way such that it'll automatically do the right thing even after we fix that bug.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This also makes an example of why it's valuable to have the test be explicit about the key facts it's relying on in its test data — if this eg.streamMessage line were explicitly saying the message is unread, instead of implicitly doing so, then it'd naturally raise the question of how that fits with the test description saying this is about not having any unreads.)

check(connection.lastRequest).isA<http.Request>()
..url.path.equals('/api/v1/messages/flags/narrow')
..bodyFields['narrow'].equals(jsonEncode([
...TopicNarrow(someChannel.streamId, TopicName(someTopic)).apiEncode(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can simplify a bit with a test helper:

Suggested change
...TopicNarrow(someChannel.streamId, TopicName(someTopic)).apiEncode(),
...eg.topicNarrow(someChannel.streamId, someTopic).apiEncode(),

Comment on lines 604 to 599
...TopicNarrow(someChannel.streamId, TopicName(someTopic)).apiEncode(),
{'operator': 'is', 'operand': 'unread'},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a type mismatch: apiEncode returns a list of ApiNarrowElement, but this last item is just a Map<String, String>. It works because it's just getting passed to jsonEncode which is pretty dynamic… but let's clean it up with uniform types. You can do that by putting an appropriate ApiNarrowElement here instead.

Comment on lines 601 to 600
check(connection.lastRequest).isA<http.Request>()
..url.path.equals('/api/v1/messages/flags/narrow')
..bodyFields['narrow'].equals(jsonEncode([
...TopicNarrow(someChannel.streamId, TopicName(someTopic)).apiEncode(),
{'operator': 'is', 'operand': 'unread'},
]));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This checks it's doing something to the message flags in this narrow — but not that it's marking as read. In particular this test would equally well pass if the implementation were changed to mark the messages as unread instead of read.

Let's add the checks that ensure what it's doing is marking as read, rather than marking as unread or setting or unsetting some other flag.

Comment on lines 29 to 25
/// if the operation fails. Updates unread counts in the UI on success.
static Future<void> markNarrowAsRead(BuildContext context, Narrow narrow) async {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This last sentence isn't accurate — this function doesn't do anything to unread counts in the UI.

(It wouldn't, because it's the model's job to drive the data that appears in the UI. But this doesn't do anything to unread counts in the model, either. If you're thinking of the PerAccountStoreWidget.of(context).unreads.handleAllMessagesReadSuccess() call at the end, see that method's doc.)

title: zulipLocalizations.errorMarkAsReadFailedTitle,
message: e.toString()); // TODO(#741): extract user-facing message better
return;
/// High-level operations that interact with the Zulip API and handle UI feedback.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"handle feedback" sounds like something that receives feedback and does something about it. These do the opposite, showing feedback to the user.

@gnprice
Copy link
Member

gnprice commented Feb 19, 2025

Let's leave out the last commit introducing ZulipAction; that change is mostly a matter of writing docs, so I think it'll be simpler if I just do that change myself rather than going through cycles of editing.

I've just sent #1366 for this part.

chimnayajith added a commit to chimnayajith/zulip-flutter that referenced this pull request Feb 19, 2025
Figma doesn't specify this icon explicitly. Based on discussions in PR zulip#1274
(zulip#1274 (comment)),
we chose this icon for consistency with the "Mark as read" option on web.

reference: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=3512-7&t=iwirdCVutQls9R0A-4
chimnayajith added a commit to chimnayajith/zulip-flutter that referenced this pull request Feb 19, 2025
Figma doesn't specify this icon explicitly. Based on discussions in PR zulip#1274
(zulip#1274 (comment)),
we chose this icon for consistency with the "Mark as read" option on web.

reference: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=3512-7&t=iwirdCVutQls9R0A-4
chimnayajith added a commit to chimnayajith/zulip-flutter that referenced this pull request Feb 20, 2025
Figma doesn't specify this icon explicitly. Based on discussions in PR zulip#1274
(zulip#1274 (comment)),
we chose this icon for consistency with the "Mark as read" option on web.

reference: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=3512-7&t=iwirdCVutQls9R0A-4
@lakshya1goel lakshya1goel force-pushed the issue1225 branch 2 times, most recently from ee04c30 to 89b9f7c Compare February 20, 2025 12:52
@lakshya1goel
Copy link
Contributor Author

Pushed the revision - PTAL @gnprice , Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integration review Added by maintainers when PR may be ready for integration
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Offer "Mark topic as read" in topic action sheet
5 participants